/* File: ast_stmt.h
 * ----------------
 * The Stmt class and its subclasses are used to represent
 * statements in the parse tree.  For each statment in the
 * language (for, if, return, etc.) there is a corresponding
 * node class for that construct. 
 *
 * pp4: You will need to extend the Stmt classes to implement
 * code generation for statements.
 */


#ifndef _H_ast_stmt
#define _H_ast_stmt

#include "list.h"
#include "ast.h"
#include <stack>
#include "hashtable.h"

class CodeGenerator;
class Decl;
class VarDecl;
class Expr;
class Location;

class Scope {
        public:
                Hashtable<Decl*> *map;
        public:
                friend ostream& operator<<(ostream& out, Scope *s);
                void insertDecl(Decl *d);
                Scope();
};
  
class Program : public Node
{
        public: 
                static stack<const char*> *labels;
                static Scope *globalScope;
  protected:
          CodeGenerator *generator;
     List<Decl*> *decls;
     
  public:
     Program(List<Decl*> *declList);
     void Check();
     void useScope();
     void Emit();
};

class Stmt : public Node
{
  public:
     Stmt();
     Stmt(yyltype loc);
     virtual int getSpace() = 0;
     virtual Location *codeGen(CodeGenerator *gen) = 0;
     virtual void useScope() = 0;
		 virtual const char* classname() { return "Stmt"; }
};

class StmtBlock : public Stmt 
{
  protected:
    List<VarDecl*> *decls;
    List<Stmt*> *stmts;
    
  public:
    StmtBlock(List<VarDecl*> *variableDeclarations, List<Stmt*> *statements);
    Location *codeGen(CodeGenerator *gen);
    void useScope();
    int getSpace();
		const char* classname() { return "StmtBlock"; }
};

  
class ConditionalStmt : public Stmt
{
  protected:
    Expr *test;
    Stmt *body;
  
  public:
    ConditionalStmt(Expr *testExpr, Stmt *body);
    virtual void useScope() = 0;
		const char* classname() { return "ConditionalStmt"; }
};

class LoopStmt : public ConditionalStmt 
{
  public:
    LoopStmt(Expr *testExpr, Stmt *body)
            : ConditionalStmt(testExpr, body) {}
    virtual void useScope() = 0;
		const char* classname() { return "LoopStmt"; }
		
};

class ForStmt : public LoopStmt 
{
  protected:
    Expr *init, *step;
  
  public:
    ForStmt(Expr *init, Expr *test, Expr *step, Stmt *body);
    Location *codeGen(CodeGenerator *gen);
    int getSpace();
    void useScope();
		const char* classname() { return "ForStmt"; }
		
};

class WhileStmt : public LoopStmt 
{
  public:
    WhileStmt(Expr *test, Stmt *body) : LoopStmt(test, body) {}
    Location *codeGen(CodeGenerator *gen);
    int getSpace();
    void useScope();
		const char* classname() { return "WhileStmt"; }
		
};

class IfStmt : public ConditionalStmt 
{
  protected:
    Stmt *elseBody;
  
  public:
    IfStmt(Expr *test, Stmt *thenBody, Stmt *elseBody);
    Location *codeGen(CodeGenerator *gen);
    int getSpace();
    void useScope();
		const char* classname() { return "IfStmt"; }
		
};

class BreakStmt : public Stmt 
{
  public:
    BreakStmt(yyltype loc) : Stmt(loc) {}
           Location *codeGen(CodeGenerator *gen);
           int getSpace();
           void useScope() {};
			 		const char* classname() { return "BreakStmt"; }
					 
};

class ReturnStmt : public Stmt  
{
  protected:
    Expr *expr;
  
  public:
    ReturnStmt(yyltype loc, Expr *expr);
    Location *codeGen(CodeGenerator *gen);
    int getSpace();
    void useScope();
		const char* classname() { return "ReturnStmt"; }
		
};

class PrintStmt : public Stmt
{
  protected:
    List<Expr*> *args;
    
  public:
    PrintStmt(List<Expr*> *arguments);
    Location *codeGen(CodeGenerator *gen);
    int getSpace();
    void useScope();
		const char* classname() { return "PrintStmt"; }
		
};


#endif
